package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.dao.model.*;
import com.wzcl.app.dao.repository.ActivityRuleRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.common.WZCL;
import com.wzcl.app.model.dto.ActivityRuleDto;
import com.wzcl.app.service.ActivityRuleInfoService;
import com.wzcl.app.service.ActivityRuleService;
import com.wzcl.app.service.ActivityService;
import com.wzcl.app.service.UserGroupService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

@Log4j2
@Service
public class ActivityRuleServiceImpl implements ActivityRuleService {

    public static final String USER_GROUP_KEY = "USER_GROUP";

    @Autowired
    private ActivityRuleRepository ruleRepository;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private UserGroupService groupService;

    @Autowired
    private ActivityRuleInfoService ruleInfoService;

    @Override
    public ActivityRule addActivityRule(ActivityRuleDto activityRuleDto) {
        ActivityRule rule = new ActivityRule();
        BeanUtils.copyProperties(activityRuleDto, rule, "id");
        //校验活动的存在性
        activityService.getAndCheckById(rule.getActivityId());
        //如果是指定用户组，则需要判断用户组是否存在
        if (WZCL.ACTIVITY_RULE_TARGET.USER_GROUP.equals(rule.getTarget())) {
            groupService.getAndCheckById(rule.getGroupId());
        }
        ActivityRule activityRule = ruleRepository.save(rule);
        //存在规则的计算规则
        if (activityRuleDto.getRuleInfoDtoList() != null && activityRuleDto.getRuleInfoDtoList().size() > 0) {
            ruleInfoService.addRuleInfoByRule(activityRule, activityRuleDto.getRuleInfoDtoList());
        }
        return activityRule;
    }

    @Override
    public ActivityRule delActivityRuleById(Integer id) {
        ActivityRule activityRule = getAndCheckById(id);
        log.info("ActivityRule:{} Physical deletion", JSON.toJSONString(activityRule));
        ruleRepository.delete(activityRule);
        return activityRule;
    }

    @Override
    public void delActivityRuleByActivityId(Integer id) {
        List<ActivityRule> ruleList = ruleRepository.findAllByActivityId(id);
        if (ruleList != null && ruleList.size() > 0) {
            log.info("ActivityRule:{} Physical deletion", JSON.toJSONString(ruleList));
            for (ActivityRule activityRule : ruleList) {
                ruleInfoService.delRuleInfoByRule(activityRule);
            }
            ruleRepository.deleteAll(ruleList);
        }
    }

    @Override
    public ActivityRule updateActivityRule(ActivityRuleDto activityRuleDto) {
        //校验获取
        ActivityRule activityRule = getAndCheckById(activityRuleDto);
        //赋值
        BeanUtils.copyProperties(activityRuleDto, activityRule, "id", "target", "activityId", "target");
        //存在规则的计算规则
        if (activityRuleDto.getRuleInfoDtoList() != null && activityRuleDto.getRuleInfoDtoList().size() > 0) {
            ruleInfoService.updateRuleInfoByRule(activityRule, activityRuleDto.getRuleInfoDtoList());
        }
        return ruleRepository.save(activityRule);
    }

    @Override
    public ActivityRule getActivityRuleById(Integer id) {
        Optional<ActivityRule> optional = ruleRepository.findById(id);
        return optional.orElse(null);
    }

    @Override
    public ActivityRule getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少规则Id");
        }
        ActivityRule activityRule = getActivityRuleById(id);
        if (activityRule == null) {
            throw new BusinessException(CodeMsg.ACTIVITY_RULE_NOT_EXIST);
        }
        return activityRule;
    }

    @Override
    public List<ActivityRule> getActivityRuleList(ActivityRuleDto activityRuleDto) {
        return ruleRepository.findAll(getSpecification(activityRuleDto), activityRuleDto.getSort());
    }

    @Override
    public MyPage<ActivityRule> getActivityRulePage(ActivityRuleDto activityRuleDto) {
        Page<ActivityRule> all = ruleRepository.findAll(getSpecification(activityRuleDto), activityRuleDto.getPageable());
        ArrayList<ActivityRule> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<ActivityRule> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.getTotalElements());
        return myPage;
    }

    @Override
    public List<ActivityRule> getActivityRuleListByActivityId(Integer activityId) {
        return ruleRepository.findAllByActivityId(activityId);
    }

    /**
     * 校验规则
     *
     * @param user 用户信息
     * @param rule 规则
     * @param data 相应参数（没有对应参数，获取后将数据存入data）
     * @return
     */
    @Override
    public Boolean checkRule(AppUser user, ActivityRule rule, Map<String, Object> data) {
        boolean flag = false;
        if (WZCL.ACTIVITY_RULE_TARGET.USER_GROUP.equals(rule.getTarget())) {
            if (!data.containsKey(USER_GROUP_KEY)) {
                UserGroup userGroup = groupService.getUserGroupById(rule.getGroupId());
                data.put(USER_GROUP_KEY, userGroup);
            }
            for (ActivityRuleInfo info : rule.getRuleInfoList()) {
                flag = checkRuleInfoUserGroup(info, user, data.get(USER_GROUP_KEY));
                if (!flag) break;
            }
        }
        return flag;
    }

    @Override
    public Long countByGroupId(Integer id) {
        return ruleRepository.countAllByGroupId(id);
    }


    /**
     * 对用户组的 包含/不包含校验
     *
     * @param ruleInfo
     * @param user
     * @param userGroup
     * @return
     */
    private boolean checkRuleInfoUserGroup(ActivityRuleInfo ruleInfo, AppUser user, Object userGroup) {
        try {
            //匿名用户直接默认为不通过
            if(user == null){
                return false;
            }
            UserGroup group = (UserGroup) userGroup;
            if (WZCL.ACTIVITY_RULE_INFO_PROPERTY.SELF.equals(ruleInfo.getProperty())) {
                Boolean contain = false;
                List<AppUser> userList = group.getUserList();
                if (userList != null && userList.size() > 0) {
                    contain = userList.contains(user);
                }
                if (WZCL.ACTIVITY_RULE_INFO_COMPARE.CONTAIN.equals(ruleInfo.getCompare())) {
                    return contain;
                } else if (WZCL.ACTIVITY_RULE_INFO_COMPARE.EXCLUDE.equals(ruleInfo.getCompare())) {
                    return !contain;
                }
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }

    private Specification<ActivityRule> getSpecification(ActivityRuleDto ruleDto) {
        return new Specification<ActivityRule>() {
            @Override
            public Predicate toPredicate(Root<ActivityRule> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (ruleDto.getActivityId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("activityId"), ruleDto.getActivityId()));
                }
                if (ruleDto.getTarget() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("target"), ruleDto.getTarget()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }
}
